package com.janetfilter.plugins.dns;

import com.janetfilter.core.models.FilterRule;

import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

public class DNSFilter {
    private static final Logger logger = Logger.getLogger(DNSFilter.class.getName());

    private static final List<FilterRule> ruleList = new ArrayList<>();
    private static final List<FilterRule> whiteList = new ArrayList<>();
    private static final Map<String, List<FilterRule>> group = new HashMap<>();

    public static void setRules(List<FilterRule> rules) {
        rules.forEach(filterRule -> {
            if (filterRule.isWhite()) {
                whiteList.add(filterRule);
            } else {
                group.computeIfAbsent(filterRule.getStrategy(), k -> new ArrayList<>()).add(filterRule);
            }
        });
    }

    public static String testQuery(String host) throws IOException {
        if (null == host) {
            return null;
        }
        logger.info(String.format("host Connection : %s", host));

        boolean white;
        if (whiteList.stream().anyMatch(FilterRule::isInverse)) {
            white = whiteList.stream().allMatch(filterRule -> filterRule.test(host));
        } else {
            white = whiteList.stream().anyMatch(filterRule -> filterRule.test(host));
        }
        logger.info(String.format("white test: %s", white));

        if (!white) {

            boolean result;

            result = group.entrySet().stream().anyMatch(entry -> {
                final boolean allMatch = entry.getValue().stream().allMatch(filterRule -> {
                    final boolean test = filterRule.test(host);
                    logger.info(String.format("test result %s : rule %s", test, filterRule));
                    return test;
                });
                if (allMatch) logger.info(String.format("test result true : strategy name %s", entry.getKey()));
                return allMatch;
            });

            logger.info(String.format("strategy test: %s", result));
            if (result) {
                throw new java.net.UnknownHostException();
            }
        }

        return host;
    }

    public static Object testReachable(InetAddress n) throws IOException {
        if (null == n) {
            return null;
        }
        logger.info(String.format("InetAddress Connection : %s", n));

        final boolean white = whiteList.stream().anyMatch(filterRule -> filterRule.test(n.getHostName()));
        logger.info(String.format("white test: %s", white));

        if (!white) {

            boolean result;

            result = group.entrySet().stream().anyMatch(entry -> {
                final boolean allMatch = entry.getValue().stream().allMatch(filterRule -> {
                    final boolean test = filterRule.test(n.getHostName());
                    logger.info(String.format("test result %s : rule %s", test, filterRule));
                    return test;
                });
                if (allMatch) logger.info(String.format("test result true : strategy name %s", entry.getKey()));
                return allMatch;
            });

            logger.info(String.format("strategy test: %s", result));
            if (result) {
                return false;
            }
        }

        return null;
    }
}
